package com.mongo.service.impl;


import com.mongo.func.SFunction;
import com.mongo.service.BaseService;
import com.mongo.service.LambdaUpdate;
import com.mongo.service.MongoMapper;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.objenesis.instantiator.util.ClassUtils;
import org.springframework.util.Assert;

import java.lang.reflect.Field;
import java.time.Duration;

import static com.mongo.util.ReflectionUtil.findField;

/**
 * mongo的lambda更新实现
 * @author xiazhun
 * @create 2022/6/8
 */
@SuppressWarnings("all")
public class LambdaMongoUpdate<T> extends BaseService<T> implements LambdaUpdate<T> {
    private final Update update;
    private final Query query;

    private Class<T> aClass;


    public Update getUpdate() {
        return update;
    }

    public Query getQuery() {
        return query;
    }

    public LambdaMongoUpdate() {
        this((T) null);
    }

    public LambdaMongoUpdate(T entity) {
        update = new Update();
        query = new Query();
        setEntity(entity);
    }

    @SuppressWarnings("all")
    public LambdaMongoUpdate(MongoMapper<T> baseMapper){
        this.aClass = baseMapper.getClazz();
        setEntity(ClassUtils.newInstance(aClass));
        setBaseMapper(baseMapper);
        update = new Update();
        query = new Query();
    }

    public LambdaMongoUpdate(Class<T> var) {
        this(ClassUtils.newInstance(var));
    }

    @Override
    public LambdaMongoUpdate<T> set(SFunction<T, ?> function, Object value) {
        return set(true, function, value);
    }

    @Override
    public LambdaMongoUpdate<T> set(boolean condition, SFunction<T, ?> function, Object value) {
        if (condition) {
            Field field = findField(function);
            Assert.notNull(field, "无法获取引用字段");
            update.set(field.getName(), value);
        }
        return this;
    }

    @Override
    public LambdaMongoUpdate<T> eq(SFunction<T, ?> function, Object value) {
        return eq(true, function, value);
    }

    @Override
    public LambdaMongoUpdate<T> eq(boolean condition, SFunction<T, ?> function, Object value) {
        if (condition) {
            Field field = findField(function);
            Assert.notNull(field, "无法获取引用字段");
            query.addCriteria(Criteria.where(field.getName()).is(value));
        }
        return this;
    }

    /**
     * 更新数据
     *
     * @return 返回更新后的数据, 查询可能为null
     */
    @Override
    public long update() {
        long res = 0;
        if (query.getQueryObject().isEmpty()) {
            throw new IllegalArgumentException("条件为空");
        }
        //如果update没有设置key,value则不更新,否则会造成数据清空
        if (!update.getUpdateObject().isEmpty()) {
            res = update(query, update);
        }
        return res;
    }

    @Override
    public long update(Query query) {
        long res = 0;
        if (query.getQueryObject().isEmpty()) {
            throw new IllegalArgumentException("条件为空");
        }
        //如果update没有设置key,value则不更新,否则会造成数据清空
        if (!update.getUpdateObject().isEmpty()) {
            res = update(query, update);
        }
        return res;
    }

    public LambdaMongoUpdate<T> maxTime(Duration duration) {
        this.query.maxTime(duration);
        return this;
    }
}
